package org.eclipse.lsp4j.jsonrpc.messages;

/**
 * Representation of tuple types.
 */
public interface Tuple {

	static <F, S> Two<F, S> two(F first, S second) {
		return new Two<>(first, second);
	}

	/**
	 * A two-tuple, i.e. a pair.
	 */
	public static class Two<F extends Object, S extends Object> implements Tuple {

		private final F first;
		private final S second;

		public Two(F first, S second) {
			this.first = first;
			this.second = second;
		}

		public F getFirst() {
			return this.first;
		}

		public S getSecond() {
			return this.second;
		}

		@Override
		public boolean equals(final Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			final var other = (Tuple.Two<?, ?>) obj;
			if (this.first == null) {
				if (other.first != null)
					return false;
			} else if (!this.first.equals(other.first))
				return false;
			if (this.second == null) {
				if (other.second != null)
					return false;
			} else if (!this.second.equals(other.second))
				return false;
			return true;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + (this.first == null ? 0 : this.first.hashCode());
			return prime * result + (this.second == null ? 0 : this.second.hashCode());
		}

		@Override
		public String toString() {
			final var builder = new StringBuilder("Tuples.Two [").append(System.lineSeparator());
			builder.append("  first = ").append(first).append(System.lineSeparator());
			builder.append("  second = ").append(second).append(System.lineSeparator());
			return builder.append("]").toString();
		}
	}

}
